﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace MAF.Common
{
    /// <summary>
    /// 默认文件存储策略，目录名，文件名都采用当前时间的
    /// </summary>
    public class DefaultFileStorageStragy : FileStorageStrategy
    {
        private int _MaxNumOfDirs;
        private int _MaxNumOfFiles;
        private string _IniFilePath;
        private List<string> _IgnoreDirList = new List<string>();

        private Dictionary<string, int> _IniDic;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="path"></param>
        /// <param name="maxNumOfDirs"></param>
        /// <param name="maxNumOfFiles"></param>
        public DefaultFileStorageStragy(string path, int maxNumOfDirs, int maxNumOfFiles)
            : base(path)
        {
            _MaxNumOfDirs = maxNumOfDirs;
            _MaxNumOfFiles = maxNumOfFiles;
            _IniFilePath = Path.Combine(this.Root, "info.ini");
            _IgnoreDirList.Add(".svn");

            // 读取ini信息,如果ini不存在，则创建之
            if (!File.Exists(_IniFilePath))
                this.CreateIniFile(_IniFilePath);

            _IniDic = this.ReadIniFile(_IniFilePath);
        }
        /// <summary>
        /// 重载构造函数
        /// </summary>
        /// <param name="ignoreDirs"></param>
        public DefaultFileStorageStragy(string path, int maxNumOfDirs, int maxNumOfFiles,string[] ignoreDirs)
            : this(path, maxNumOfDirs, maxNumOfFiles)
        {
            _IgnoreDirList.AddRange(ignoreDirs);
        }
        #region 重写两个钩子方法

        /// <summary>
        /// 策略：根目录下有限的目录个数，每个目录有限的文件个数。
        ///       目录名是当前时间的十六进制字符串，并且目录的数量不能超过最大值
        ///       文件名是当前时间的十六进制字符串，并且文件数不能超过最大值
        /// </summary>
        private string _Filename = string.Empty;
        protected override string[] DirAndFileName
        {
            get
            {
                string[] result = new string[2];

                // 寻找已有文件夹
                foreach (KeyValuePair<string, int> kvp in _IniDic)
                {
                    if (_MaxNumOfFiles > kvp.Value)
                    {
                        result[0] = kvp.Key;
                    }
                }
                
                if( string.IsNullOrEmpty(result[0]) )
                {
                    if(_MaxNumOfDirs <= _IniDic.Count)  // 如果根目录已满，报错
                        throw new Exception("此根目录下的文件夹数已达到存储策略的最大值");
                    else                                // 否则创建一个新的文件夹
                        result[0] = this.Name;
                }
                result[1] = this.Name;

                return result;
            }
        }

        /// <summary>
        /// 修改Ini文件,Save和Delete时会调用此方法
        /// </summary>
        /// <param name="path"></param>
        protected override void UpdateConfig(string[] dirAndFilename,UpdateType type)
        {
            string path = _IniFilePath;
            Dictionary<string, int> dirs = _IniDic;

            if (_IniDic.ContainsKey(dirAndFilename[0]))
            {
                if (UpdateType.Save == type)
                    _IniDic[dirAndFilename[0]] += 1;
                else if (UpdateType.Delete == type)
                    _IniDic[dirAndFilename[0]] -= 1;
            }
            else
            {
                _IniDic[dirAndFilename[0]] = 1;
            }

            List<string> items = new List<string>();
            foreach (KeyValuePair<string, int> kvp in dirs)
            {
                items.Add(kvp.Key + "=" + kvp.Value);
            }
            File.WriteAllText(path, string.Join("\r\n", items.ToArray()));
        }
        #endregion

        /// <summary>
        /// 创建Ini文件
        /// </summary>
        private void CreateIniFile(string path)
        {
            string[] dirs = Directory.GetDirectories(this.Root);
            string[] files;
            List<string> items = new List<string>();
            string dirName;
            for (int i = 0, len = dirs.Length; i < len; i++)
            {
                files = Directory.GetFiles(dirs[i]);
                dirName = dirs[i].Replace(this.Root,"").Trim('/','\\');
                if( !_IgnoreDirList.Contains(dirName) )
                    items.Add(dirName + "=" + files.Length);
            }
            File.WriteAllText(path, string.Join("\r\n", items.ToArray()));
        }

        /// <summary>
        /// 读取Ini文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private Dictionary<string, int> ReadIniFile(string path)
        {
            string[] ss = File.ReadAllLines(path);
            Dictionary<string,int> dirs = new Dictionary<string, int>();
            
            string s;
            string[] temp;
            for (int i = 0, len = ss.Length; i < len; i++)
            {
                if (string.IsNullOrEmpty(s = ss[i].Trim())) 
                    continue;

                temp = s.Split(" =".ToCharArray(),StringSplitOptions.RemoveEmptyEntries);
                if (2 != temp.Length)
                    continue;

                int r; int.TryParse(temp[1],out r);
                dirs[temp[0]] = r;
            }
            return dirs;
        }

        /// <summary>
        /// 命名，目录名或文件名
        /// 目前采用当前时间的16进制表示,或许会改为用Base64表示
        /// </summary>
        private string Name
        {
            get{ return System.Convert.ToString(DateTime.Now.ToBinary(), 16); }
        }
    }
}
